package com.yeyks.commonReference.service.vip.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yeyks.account.dal.domain.AccountInfo;
import com.yeyks.common.base.Arguments;
import com.yeyks.common.dto.AccountPayAccountDTO;
import com.yeyks.common.utils.IdWorkerUtil;
import com.yeyks.common.utils.RedisUtil;
import com.yeyks.commonReference.pojo.param.minivipcard.MiniCardWithdrawalParam;
import com.yeyks.commonReference.service.account.AccountInfoService;
import com.yeyks.commonReference.service.vip.MiniCardCommissionBillService;
import com.yeyks.commonReference.service.vip.MiniCardCommissionOverviewService;
import com.yeyks.commonReference.service.vip.MiniCardWithdrawalOrderService;
import com.yeyks.vip.dal.domain.MiniCardCommissionBill;
import com.yeyks.vip.dal.domain.MiniCardCommissionOverview;
import com.yeyks.vip.dal.dao.MiniCardCommissionOverviewMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yeyks.vip.dal.domain.MiniCardWithdrawalOrder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;


/**
 * <p>
 * 精选小vip售卡佣金总览表 服务实现类
 * </p>
 *
 * @author yun
 * @since 2020-01-06
 */
@Service
@Slf4j
public class MiniCardCommissionOverviewServiceImpl extends ServiceImpl<MiniCardCommissionOverviewMapper, MiniCardCommissionOverview> implements MiniCardCommissionOverviewService {

    @Autowired
    private MiniCardWithdrawalOrderService withdrawalOrderService;
    @Autowired
    private MiniCardCommissionBillService billService;
    @Autowired
    private AccountInfoService accountInfoService;
    @Autowired
    private RedisUtil redisUtil;
    private static final String KEY_WITHDRAW = "Lock:MiniCardCommissionOverviewServiceImpl:withdraw";
    private static final String KEY_ORDERCOMMISSION = "Lock:MiniCardCommissionOverviewServiceImpl:orderCommission";
    private static final String KEY_REJECT = "Lock:MiniCardCommissionOverviewServiceImpl:orderCommission";

    /**
     * 获取用户的账户信息
     *
     * @param accountId   账户id
     * @param accountType 账户类型 {@link MiniCardCommissionOverview}
     * @return
     */
    @Override
    public MiniCardCommissionOverview getOverview(Integer accountId, Integer accountType) {
        Arguments.intIsNull(accountId, "账户id不能为空");
        Arguments.intIsNull(accountType, "账户类型不能为空");
        MiniCardCommissionOverview overview = baseMapper.selectOne(new QueryWrapper<MiniCardCommissionOverview>()
                .eq(MiniCardCommissionOverview.ACCOUNT_ID, accountId)
                .eq(MiniCardCommissionOverview.ACCOUNT_TYPE, accountType).last("limit 1"));
        if (null == overview) {
            Date date = new Date();
            MiniCardCommissionOverview newOverview = new MiniCardCommissionOverview(accountId, 0, 0, 0, accountType, date, date);
            if (1 == baseMapper.insert(newOverview)) {
                return newOverview;
            }
        }
        return overview;
    }

    /**
     * 佣金提现
     *
     * @param param {@link MiniCardWithdrawalParam}
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean withdraw(MiniCardWithdrawalParam param) {
        //1.校验该用户是否可以提现
        Arguments.isFalse(withdrawalOrderService.checkWithDraw(param), "您暂时不能提现");
        Date date = new Date();
        redisUtil.runWithLock(KEY_WITHDRAW, () -> {
            //查询用户账户
            MiniCardCommissionOverview overview = getOverview(param.getAccountId(), param.getAccountType());
            Arguments.beanIsNull(overview, "该账户不存在");
            overview.setUpdateTime(date);
            Arguments.isTrue(overview.getRemainAmount() <= 0, "余额不足");
            param.setAmount(overview.getRemainAmount());
            overview.setTotalOutAmount(overview.getTotalOutAmount() + overview.getRemainAmount());
            overview.setRemainAmount(0);
            Arguments.isFalse(1 == baseMapper.updateById(overview), "提现异常");
            //生成提现订单并保存
            MiniCardWithdrawalOrder order = getMiniCardWithdrawalOrder(param);
            //写入提现明细
            saveBill(param.getAccountId(), param.getAmount(), order.getOrderNo(), MiniCardCommissionBill.Type.out);
            return true;
        });
        return true;
    }

    /**
     * 订单返佣
     *
     * @param accountId   账户id
     * @param accountType 账户类型
     * @param orderNo     订单号
     * @param amount      佣金
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean orderCommission(Integer accountId, Integer accountType, String orderNo, Integer amount) {
        if (null == amount || amount <= 0) {
            return true;
        }
        redisUtil.runWithLock(KEY_ORDERCOMMISSION, () -> {
            MiniCardCommissionOverview overview = getOverview(accountId, accountType);
            if (null == overview) {
                log.info("会员卡售卖返佣账户不存在orderNo = {}", orderNo);
                return false;
            }
            Date date = new Date();
            overview.setTotalInAmount(overview.getTotalInAmount() + amount);
            overview.setRemainAmount(overview.getRemainAmount() + amount);
            overview.setUpdateTime(date);
            if (1 != baseMapper.updateById(overview)) {
                log.info("会员卡售卖返佣账户新增异常orderNo = {}", orderNo);
                return false;
            }
            //写入提现明细
            saveBill(accountId, amount, orderNo, MiniCardCommissionBill.Type.in);
            return true;
        });
        return true;
    }

    /**
     * 提现申请拒绝
     *
     * @param orderNo 提现订单号
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean reject(String orderNo) {
        Date date = new Date();
        Arguments.strIsNull(orderNo, "订单号不能为空");
        redisUtil.runWithLock(KEY_REJECT, () -> {
            MiniCardWithdrawalOrder order = withdrawalOrderService.selectByOrderNo(orderNo);
            Arguments.beanIsNull(order, "该提现订单不存在");
            Arguments.isFalse(MiniCardWithdrawalOrder.Status.wait.value().equals(order.getStatus()), "订单非审核中状态");
            //根据订单号和提现状态查询明细
            MiniCardCommissionBill bill = billService.getOne(new QueryWrapper<MiniCardCommissionBill>()
                    .eq(MiniCardCommissionBill.ORDER_NO, order.getOrderNo())
                    .eq(MiniCardCommissionBill.ACCOUNT_ID, order.getAccountId())
                    .eq(MiniCardCommissionBill.TYPE, 1)
                    .eq(MiniCardCommissionBill.OPERATOR_TYPE, MiniCardCommissionBill.Type.out.value())
                    .eq(MiniCardCommissionBill.REMARK, MiniCardCommissionBill.Type.out.desc())
            );
            Arguments.beanIsNull(bill, "该提现订单对应佣金明细不存在");
            //查询该账户
            MiniCardCommissionOverview overview = getOverview(order.getAccountId(), order.getAccountType());
            Arguments.beanIsNull(overview, "该提现订单对应账户不存在");
            //修改金额
            overview.setRemainAmount(overview.getRemainAmount() + bill.getOperatorAmount());
            overview.setTotalOutAmount(overview.getTotalOutAmount() - bill.getOperatorAmount());
            overview.setUpdateTime(date);
            Arguments.isFalse(1 == baseMapper.updateById(overview), "提现拒绝异常");
            //写入提现明细
            saveBill(overview.getAccountId(), bill.getOperatorAmount() , orderNo, MiniCardCommissionBill.Type.reject);
            return true;
        });
        return true;
    }

    /**
     * 保存明细
     *
     * @param accountId 账户id
     * @param amount    操作金额
     * @param orderNo   订单号
     * @param enumType  枚举
     */
    private void saveBill(Integer accountId, Integer amount, String orderNo, MiniCardCommissionBill.Type enumType) {
        MiniCardCommissionBill bill = new MiniCardCommissionBill();
        bill.setAccountId(accountId);
        bill.setOrderNo(orderNo);
        bill.setOperatorAmount(amount);
        bill.setType(1);
        bill.setOperatorType(enumType.value());
        bill.setRemark(enumType.desc());
        bill.setCreateTime(new Date());
        //保存明细
        Arguments.isFalse(billService.save(bill), "明细添加异常");
    }

    /**
     * 生成提现订单并保存
     *
     * @param param
     * @return
     */
    private MiniCardWithdrawalOrder getMiniCardWithdrawalOrder(MiniCardWithdrawalParam param) {
        Date date = new Date();
        MiniCardWithdrawalOrder order = new MiniCardWithdrawalOrder();
        String orderNo = IdWorkerUtil.nextStrId();
        order.setOrderNo(orderNo);
        //查询该账户（由于之前判断是否可以提现时已经校验过账户信息，这里直接用即可）
        AccountInfo accountInfo = accountInfoService.getById(param.getAccountId());
        order.setAccountId(param.getAccountId());
        order.setAccountName(accountInfo.getUsername());
        order.setAccountPhone(accountInfo.getPhone());
        order.setAccountType(param.getAccountType());
        //银行账户信息添加
        try {
            String bankData = accountInfo.getExtraInfo();
            AccountPayAccountDTO payAccountDTO = JSONUtil.toBean(bankData, AccountPayAccountDTO.class);
            order.setBankUserName(payAccountDTO.getPayAccounts().getUserName());
            order.setBankName(payAccountDTO.getPayAccounts().getBankName());
            order.setBankBranchName(payAccountDTO.getPayAccounts().getBranchBankName());
            order.setBankCard(payAccountDTO.getPayAccounts().getBankCard());
        } catch (Exception e) {
            e.printStackTrace();
            log.info("提现账户银行卡信息有误AccountInfo = {}", accountInfo);
        }
        order.setAmount(param.getAmount());
        //写死小v卖卡提成
        order.setOrderType(0);
        order.setStatus(1);
        order.setDeleteFlag(0);
        order.setCreateTime(date);
        order.setUpdateTime(date);
        order.setRemark(MiniCardWithdrawalOrder.Status.wait.desc());
        //提现订单保存
        Arguments.isFalse(withdrawalOrderService.save(order), "生成提现订单异常");
        return order;
    }
}

























